import { cloneDeep } from 'lodash-es';
import {
  ITEM_RARITY,
  type EquipmentItemConfig,
  type ItemRarity,
} from '../../data/item/type';
import type {
  EquipmentInventorySlotItemPayload,
  EquipmentInventorySlotItemPayloadBaseAttrs,
} from '../../model/inventory/type';

/** 装备掉落品阶权重 */
const EQUIPMENT_DROP_RARITY_WEIGHT: Record<ItemRarity, number> = {
  [ITEM_RARITY.COMMON]: 100000,
  [ITEM_RARITY.INFERIOR]: 50000,
  [ITEM_RARITY.MEDIUM]: 20000,
  [ITEM_RARITY.SUPERIOR]: 8000,
  [ITEM_RARITY.SUPREME]: 2000,
  [ITEM_RARITY.IMMORTAL]: 500,
  [ITEM_RARITY.PERFECT]: 100,
  [ITEM_RARITY.INNATE]: 0,
  [ITEM_RARITY.TREASURE]: 0,
};

export const RARITY_ROLL_MULTIPLIER: Record<ItemRarity, number> = {
  [ITEM_RARITY.COMMON]: 100,
  [ITEM_RARITY.INFERIOR]: 130,
  [ITEM_RARITY.MEDIUM]: 169,
  [ITEM_RARITY.SUPERIOR]: 220,
  [ITEM_RARITY.SUPREME]: 286,
  [ITEM_RARITY.IMMORTAL]: 371,
  [ITEM_RARITY.PERFECT]: 483,
  [ITEM_RARITY.INNATE]: 627,
  [ITEM_RARITY.TREASURE]: 815,
};

const CALCULATE_ENHANCE_SUCCESS_RATE_CONFIG = {
  baseSuccess: 0.95, // +1 的起始成功率
  decay: 0.735, // 衰减系数，越大掉得越慢
  floor: 0.01, // 最低保底 1 %
};

export class ItemCalculator {
  /** 计算随机掉落装备品质 */
  static rollDropEquipmentRarity(): ItemRarity {
    const entries = (
      Object.entries(EQUIPMENT_DROP_RARITY_WEIGHT) as [ItemRarity, number][]
    ).filter(([, w]) => w > 0);

    if (entries.length === 0) {
      throw new Error('至少需要一个权重大于 0 的品质');
    }

    const total = entries.reduce((sum, [, w]) => sum + w, 0);
    let r = Math.random() * total;

    for (const [rarity, weight] of entries) {
      r -= weight;
      if (r < 0) return rarity;
    }
    return ITEM_RARITY.COMMON;
  }

  /** 随机装备属性 */
  static rollEquipmentBaseAttributes(
    config: EquipmentItemConfig,
    rarity: ItemRarity
  ): EquipmentInventorySlotItemPayloadBaseAttrs[] {
    const attrs: EquipmentInventorySlotItemPayloadBaseAttrs[] = [];
    config.baseAttr.forEach((r) => {
      const rarityMultiplier = RARITY_ROLL_MULTIPLIER[rarity];
      const value = Math.floor(r.base * (rarityMultiplier / 100));
      attrs.push({
        prop: r.prop,
        value,
      });
    });
    return attrs;
  }

  /** 计算装备强化成功率 */
  static calculateEnhanceSuccessRate(level: number): number {
    if (level <= 0) return 1;
    if (level >= 20) return CALCULATE_ENHANCE_SUCCESS_RATE_CONFIG.floor;
    const rate =
      CALCULATE_ENHANCE_SUCCESS_RATE_CONFIG.baseSuccess *
      Math.pow(CALCULATE_ENHANCE_SUCCESS_RATE_CONFIG.decay, level - 1);
    return Math.max(rate, CALCULATE_ENHANCE_SUCCESS_RATE_CONFIG.floor);
  }

  /** 计算强化失败保底概率值增加的多少 */
  static calculateEnhanceFailProtection(level: number): number {
    if (level <= 1) return 0.04;
    if (level >= 19) return 0.005;
    const ratio = (level - 1) / (19 - 1);
    return 0.04 - ratio * (0.04 - 0.005);
  }

  /** 装备强化 */
  static enhanceEquipment(
    payload: EquipmentInventorySlotItemPayload
  ): EquipmentInventorySlotItemPayload {
    const enhance = cloneDeep(payload.enhance);
    const successRate = ItemCalculator.calculateEnhanceSuccessRate(
      enhance.level
    );

    if (Math.random() < successRate + enhance.failProtection) {
      enhance.level += 1;
      enhance.failProtection = 0;
    } else {
      enhance.failProtection += ItemCalculator.calculateEnhanceFailProtection(
        enhance.level
      );
    }

    return {
      ...payload,
      enhance,
    };
  }

  /** 计算装备最终属性 */
  static calculateFinalEquipmentAttributes(
    payload: EquipmentInventorySlotItemPayload
  ): EquipmentInventorySlotItemPayloadBaseAttrs[] {
    const level = payload.enhance.level;
    if (level <= 0) return payload.baseAttrs;
    return payload.baseAttrs.map((attr) => {
      return {
        ...attr,
        value: Math.floor(attr.value * (1 + level * 0.05)),
      };
    });
  }
}
